﻿///////////////////////////////////////////////////////////////////////////////////////////////
// System.Text.Parsing - © 2011 Sebastien Pellizzari
// Released under the MIT License (http://www.opensource.org/licenses/mit-license.php)
///////////////////////////////////////////////////////////////////////////////////////////////

namespace System.Text.Parsing
{
    /// <summary>Represents a token definition in a tokernizer grammar.</summary>
    public sealed class GrammarToken
    {
        private readonly GrammarTextValue _name;                    // Token name.
        private readonly GrammarTextValue _definition;              // Token definition string.
        private readonly GrammarTokenGroup _group;                  // Token group.
        private readonly GrammarSourceRange _sourceInfo;            // Source info.
        private readonly GrammarPropertyCollection _properties;     // The properties.
        private readonly GrammarCodeBlockCollection _codeBlocks;    // The code blocks.

        //-----------------------------------------------------------------------
        //     Properties
        //-----------------------------------------------------------------------

        /// <summary>Gets the name of the token.</summary>
        public GrammarTextValue Name { get { return _name; } }
        /// <summary>Gets the token definition.</summary>
        public GrammarTextValue Definition { get { return _definition; } }
        /// <summary>Gets the group that contains the token, if any.</summary>
        public GrammarTokenGroup Group { get { return _group; } }
        /// <summary>Gets the token source information.</summary>
        public GrammarSourceRange SourceInfo { get { return _sourceInfo; } }
        /// <summary>Gets the collection of properties.</summary>
        public GrammarPropertyCollection Properties { get { return _properties; } }
        /// <summary>Gets the collection of code blocks.</summary>
        public GrammarCodeBlockCollection CodeBlocks { get { return _codeBlocks; } }

        //-----------------------------------------------------------------------
        //     Constructors
        //-----------------------------------------------------------------------

        /// <summary>Initializes an instance of the <see cref="GrammarToken"/> class.</summary>
        /// <param name="name">The name of the token.</param>
        /// <param name="definition">The token definition.</param>
        /// <param name="group">The group that contains the token definition, if any.</param>
        /// <param name="sourceInfo">Source information.</param>
        public GrammarToken(GrammarTextValue name, GrammarTextValue definition, GrammarTokenGroup group, GrammarSourceRange sourceInfo)
        {
            if (name.Text == null) throw new ArgumentNullException("name.Text");
            if (definition.Text == null) throw new ArgumentNullException("definition.Text");
            _name = name;
            _group = group;
            _definition = definition;
            _sourceInfo = sourceInfo;
        }

        // Constructor.
        internal GrammarToken(GrammarTextValue name, GrammarTextValue definition, GrammarTokenGroup group, GrammarSourceRange sourceInfo,
            GrammarPropertyCollection properties, GrammarCodeBlockCollection codeBlocks)
        {
            if (name.Text == null) throw new ArgumentNullException("name.Text");
            if (definition.Text == null) throw new ArgumentNullException("definition.Text");
            _name = name;
            _group = group;
            _definition = definition;
            _sourceInfo = sourceInfo;
            _properties = properties;
            _codeBlocks = codeBlocks;
        }

        //-----------------------------------------------------------------------
        //     Methods
        //-----------------------------------------------------------------------

        /// <summary>Copies properties from parent groups into the property list of current token when they're not already present.</summary>
        public void FlattenProperties()
        {
            var group = _group;
            while (group != null)
            {
                // For each property in the group, add it if it doesn't exist.
                foreach (var property in group.Properties)
                    if (!_properties.Contains(property.Name.Text))
                        _properties.Add(property);

                // Go to next.
                group = group.ParentGroup;
            }
        }

        /// <summary>Copies codeblocks from parent groups into the codeblock list of current token when they're not already present.</summary>
        public void FlattenCodeBlocks()
        {
            var group = _group;
            while (group != null)
            {
                // For each code block in the group, add it if it doesn't exist.
                foreach (var codeBlock in group.CodeBlocks)
                    if (!_codeBlocks.Contains(codeBlock.Name.Text))
                        _codeBlocks.Add(codeBlock);

                // Go to next.
                group = group.ParentGroup;
            }
        }
    }
}
